#pragma once

#include<iostream>
#include<vector>
#include<pthread.h>
#include <cstdlib>
#include <ctime>
#include <sys/types.h>
#include<unistd.h>
#include"sem.h"

#define g_default_nu 5

template<class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_default_nu)
    :ring_queue_(default_num)
    ,num_(default_num)
    ,space_sem_(default_num)
    ,data_sem_(0)
    {
        pthread_mutex_init(&clock, nullptr);
        pthread_mutex_init(&plock, nullptr);
    }

    void push(const T& data)
    {
        space_sem_.p();
        pthread_mutex_lock(&plock);
        ring_queue_[p_step++] = data;
        p_step %= num_;
        pthread_mutex_unlock(&plock);
        data_sem_.v();
    }

    void pop(T *out)
    {
        data_sem_.p();
        pthread_mutex_lock(&clock);
        *out = ring_queue_[c_step++];
        c_step %= num_;
        pthread_mutex_unlock(&clock);
        space_sem_.v();
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&plock);
    }

    

private:
    std::vector<T> ring_queue_;
    int num_;
    int c_step; // 消费下标
    int p_step; // 生产下标
    Sem space_sem_;
    Sem data_sem_;
    pthread_mutex_t clock;
    pthread_mutex_t plock;
};
